//#include <iostream>
//#include <fstream>
//#include <stdlib.h>
//#include <map>
#include <string>
#include <list>

#include "MiddlewareCliente.h"

#include "../Common/CommonTypes.h"
#include "../Common/Config.h"

#include "../../Framework/Shared/sem.h"
#include "../../Framework/Shared/shptr.h"
#include "../../Framework/Shared/msgqueue.h"
#include "../../Framework/Comunicaciones/tcpsocket.h"
#include "../../Framework/Common/utiles.h"
#include "../../Framework/IO/log.h"

using std::string;
using std::list;

using middleware::common::ListaReceptores;
using middleware::common::Direccion;
using middleware::common::PDUPuntoAPunto;
using middleware::common::Secuencia;

using namespace framework::io;

namespace middleware {

namespace comunicaciones {

/**
 * Estructura del token. Preliminar! Por ahora tiene solo un entero que
 * cada host incrementa antes de devolver.
 */
typedef struct {
    Secuencia n;
} token_t;

/**
 * Callback de la señal SIGINT para los procesos cliente y servidor.
 * Desconecta el socket antes de terminar.
 */
//void sigint_handler(int signal);

/**
 * Clase para administrar el anillo.
 */
class GestorAnillo {

	/**
	 * Semáforo para sincronizar los procesos cliente y servidor.
	 */
	Semaphore sem;

	/**
	 * Puntero compartido entre cliente y servidor para almacenar el token.
	 */
	SharedPointer<token_t, 1> token;

	/**
	 * Socket utilizado para enviar y recibir el token.
	 */
	TCPSocket sock;

	/**
	 * Dirección del sucesor de este nodo en el anillo.
	 */
	Direccion sucesor;

	/**
	 * Indica si es el primer host en el anillo
	 */
	bool primero;

	/**
	 * PID de los procesos cliente y servidor.
	 */
	pid_t pidsvr, pidclt;

	/**
	 * Cola de unicast.
	 */
	MessageQueue& qalc;

	/**
	 * Cola de mensajes multicast.
	 */
	MessageQueue& qrng;

	/**
	 * Lista de receptores
	 */
	ListaReceptores& receptores;

	/**
	 * Proceso servidor. Recibe una conexión del host precedente en el anillo.
	 * Una vez conectado, recibe el token y levanta el semáforo para activar el
	 * proceso cliente.
	 */
	void servidor();

	/**
	 * Proceso cliente. Intenta conectarse con el siguiente host en el anillo.
	 * Luego de establecida la conexión, espera en el semáforo el arribo del token.
	 * Finalmente, procesa el token y lo envía al siguiente host en el anillo.
	 */
	void cliente();

	/**
	 * Inicializa los recursos de IPC
	 */
	bool inicializar();

	/**
	 * Lanza el proceso servidor
	 */
	bool lanzarServidor();

	/**
	 * Lanza el proceso cliente
	 */
	bool lanzarCliente();

	/**
	 *
	 */
	Secuencia enviarMensajesPendientes(Secuencia n);

	void enviarMulticast(PDUPuntoAPunto& pdu);

	void enviarUnicast(PDUPuntoAPunto& pdu);

public:

	GestorAnillo(Direccion sucesor, bool primero);
	virtual ~GestorAnillo();

	bool run();
	void stop();
};

}

}
